Vice President of Operations, Europe
140 developers, testers, product & engineering managers & others
export class Hero {
constructor(readonly position: Point, readonly facing: Direction = "down") {}
move(direction: Direction): Hero {
return new Hero(this.position.move(direction), direction)
}
face(direction: Direction): Hero {
return new Hero(this.position, direction)
}
}
export class Map {
readonly size: { readonly width: number; readonly height: number }
private readonly tiles: readonly Tile[][]
*layer(layer: Tile.Layer): Generator {
for (const tile of this.tiles.flat())
if (tile.layer == layer)
yield tile
}
*items(): Generator- {
for (const tile of this.tiles.flat())
if (tile.item)
yield tile.item
}
}
export abstract class Tile {
abstract readonly type: Type
abstract readonly layer: Layer
abstract walkable: boolean
constructor(public readonly position: Point, public readonly map: Map, public readonly item?: Item) {}
place(item: Item): Tile {
return new types[this.type]!(this.position, this.map, item)
}
collect(): Tile {
return new types[this.type]!(this.position, this.map) as Tile
}
}
export class Item {
constructor(readonly type: Item.Type, readonly position: Point) {}
}
export class Game {
constructor(readonly map: Map, readonly hero: Hero) {}
move(direction: Direction): Game {
let hero = this.hero.move(direction)
const tile = this.map.get(hero.position)
if (!tile.walkable)
hero = this.hero.face(direction)
const map = tile.walkable && tile.item ? this.map.set(tile.collect()) : this.map
return new Game(map, hero)
}
static async fetch(url: string): Promise {
const level = await (await fetch(url)).json()
return Level.is(level) ? Level.load(level) : undefined
}
}
@Component({ tag: "aron-game", styleUrl: "style.css", scoped: true, })
export class AronGame implements ComponentWillLoad {
@State() game?: model.Game
async componentWillLoad(): Promise {
this.game = await model.Game.fetch("/assets/levels/level0.json")
}
render() {
return <Host> {!this.game ? "loading.." : (
<Fragment>
<aron-layer layer="ground" map={this.game.map}></aron-layer>
<aron-items map={this.game.map}></aron-items>
<aron-hero hero={this.game.hero}></aron-hero>
<aron-layer layer="canopy" map={this.game.map}></aron-layer>
</Fragment>
)}</Host> }
}
@Listen("keydown", { target: "window" })
onKeyDown(event: KeyboardEvent) {
let direction: model.Direction | undefined
switch (event.key) {
case "ArrowLeft": direction = "left"; break
case "ArrowRight": direction = "right"; break
case "ArrowUp": direction = "up"; break
case "ArrowDown": direction = "down"; break
}
if (direction)
this.game = this.game?.move(direction)
}
@Component({ tag: "aron-layer", styleUrl: "style.css", scoped: true, })
export class AronLayer {
@Prop() layer: model.Tile.Layer
@Prop() map: model.Map
render() {
return (
<Host>
{[...this.map.layer(this.layer)].map(tile => (
<aron-tile tile={tile}></aron-tile>
))}
</Host>
)
}
}
@Component({ tag: "aron-tile", styleUrl: "style.css", scoped: true, })
export class AronTile {
@Prop() tile: model.Tile
render() {
return <Host
style={{
left: (this.tile.position.x * 64).toString() + "px",
top: (this.tile.position.y * 64).toString() + "px",
}}>
<img src={`/assets/tiles/${this.tile.type}.svg`} />
</Host>
}
}
@Component({ tag: "aron-hero", styleUrl: "style.css", scoped: true,})
export class AronHero {
@Prop() hero: model.Hero
render() {
return (
<Host
style={{
left: (this.hero.position.x * 64).toString() + "px",
top: (this.hero.position.y * 64).toString() + "px",
}}>
<img src={`/assets/hero/${this.hero.facing}.svg`} />
</Host>
)
}
}
:host {
display: block;
position: absolute;
}
:host {
transition: left 0.5s ease-in-out, top 0.5s ease-in-out;
}
Simon Mika · simon.mika@cogneco.se · 0707-680 380